home *** CD-ROM | disk | FTP | other *** search
/ PC World Interactive 7 / PC World Interactive 7.iso / program / ctutor.exe / TEXT / CHAP06.TXT < prev    next >
Text File  |  1994-05-15  |  18KB  |  406 lines

  1.  
  2.     
  3.     
  4.                                                         Chapter 6
  5.                                                THE C PREPROCESSOR
  6.  
  7. AIDS TO CLEAR PROGRAMMING
  8. -----------------------------------------------------------------
  9. The preprocessor is a program that is executed just prior to the 
  10. execution of the compiler.  It's operation is transparent to you 
  11. but it does a very important job.  It removes all comments from 
  12. the source and performs a lot of textual substitution based on 
  13. your code, passing the result to the compiler for the actual 
  14. compilation of your code.
  15.  
  16. Load and display the file named DEFINE.C for     ================
  17. your first look at some defines and macros.          DEFINE.C
  18. Notice lines 4 through 7 of the program, each    ================
  19. starting with #define.  This is the way all 
  20. defines and macros are defined.  Before the actual compilation 
  21. starts, the compiler goes through a preprocessor pass to resolve 
  22. all of the defines.  In the present case, it will find every 
  23. place in the program where the combination START is found and it 
  24. will replace it with the 0 since that is the definition.  The 
  25. compiler itself will never see the word START, so as far as the 
  26. compiler is concerned, the zeros were always there.  Note that if 
  27. the string is found in a string constant or in a comment, it will 
  28. not be changed.
  29.  
  30. It should be clear to you that putting the word START in your 
  31. program instead of the numeral 0 is only a convenience to you and 
  32. actually acts like a comment since the word START helps you to 
  33. understand what the zero is used for.
  34.  
  35. In the case of a very small program, such as that before you, it 
  36. doesn't really matter what you use.  If, however, you had a 2000 
  37. line program before you with 27 references to START, it would be 
  38. a completely different matter.  If you wanted to change all of 
  39. the STARTs in the program to a new number, it would be simple to 
  40. change the one #define statement to the new value.  If this 
  41. technique were not used, it would be difficult to find and 
  42. change all of the references to it manually, and possibly 
  43. disastrous if you missed one or two of the references.
  44.  
  45. In the same manner, the preprocessor will find all occurrences of 
  46. the word ENDING and change them to 9, then the compiler will 
  47. operate on the changed file with no knowledge that ENDING ever 
  48. existed.
  49.  
  50. It is a fairly common practice in C programming to use all 
  51. capital letters for a symbolic constant such as START and ENDING 
  52. and use all lower case letters for variable names.  You can use 
  53. any method you choose since it is mostly a matter of personal 
  54. taste.
  55.  
  56.  
  57.                                                          Page 6-1
  58.  
  59.                                    Chapter 6 - The C Preprocessor
  60.      
  61. IS THIS REALLY USEFUL?
  62. -----------------------------------------------------------------
  63. When we get to the chapters discussing input and output, we will 
  64. need an indicator to tell us when we reach the end-of-file of an 
  65. input file.  Since different compilers use different numerical 
  66. values for this, although most use a minus 1, we will write the 
  67. program with a #define to define the EOF used by our particular 
  68. compiler.  If, at some later date, we change to a new compiler, 
  69. it is a simple matter to change this one #define to fix the 
  70. entire program.  In essentially all C compilers, the EOF is 
  71. defined in the STDIO.H file.  You can observe this for yourself 
  72. by examining the contents of the STDIO.H file that was supplied 
  73. with your compiler.
  74.  
  75.  
  76. WHAT IS A MACRO?
  77. -----------------------------------------------------------------
  78. A macro is nothing more than another define, but since it is 
  79. capable of at least appearing to perform some logical decisions 
  80. or some math functions, it has a unique name.  Consider line 6 of 
  81. the program on your screen for an example of a macro.  In this 
  82. case, anytime the preprocessor finds the word MAX followed by a 
  83. group in parentheses, it expects to find two terms in the 
  84. parentheses and will do a replacement of the terms into the 
  85. second part of the definition.  Thus the first term will replace 
  86. every A in the second part of the definition and the second term 
  87. will replace every B in the second part of the definition.  When 
  88. line 15 of the program is reached, index will be substituted for 
  89. every A, and count will be substituted for every B.  Once again, 
  90. it must be stated that string constants and comments will not be 
  91. affected.  Remembering the cryptic construct we studied a couple 
  92. of chapters ago will reveal that mx will receive the maximum 
  93. value of index or count.  In like manner, the MIN macro will 
  94. result in mn receiving the minimum value of index or count.  
  95. These two particular macros are very common in C programs.
  96.  
  97. When defining a macro, it is imperative that there is no space 
  98. between the macro name and the opening parenthesis.  If there is 
  99. a space, the compiler cannot determine that it is a macro, but 
  100. will handle it like a simple substitution define statement.
  101.  
  102. The results of the macro usage are then printed out in line 17.  
  103. There are a lot of seemingly extra parentheses in the macro 
  104. definition but they are not extra, they are essential.  We will 
  105. discuss the extra parentheses in our next example program.  Be 
  106. sure to compile and execute DEFINE.C before going on to the next 
  107. example program.
  108.  
  109.  
  110.  
  111.  
  112.  
  113.  
  114.  
  115.                                                          Page 6-2
  116.  
  117.                                    Chapter 6 - The C Preprocessor
  118.  
  119. LET'S LOOK AT A WRONG MACRO
  120. -----------------------------------------------------------------
  121. Load the file named MACRO.C and display it on   =================
  122. your screen for a better look at a macro and         MACRO.C
  123. its use.  Line 4 defines a macro named WRONG    =================
  124. that appears to evaluate the cube of A, and 
  125. indeed it does in some cases, but it fails miserably in others.  
  126. The second macro named CUBE actually does get the cube in all 
  127. cases.
  128.  
  129. Consider the program itself where the CUBE of i+offset is 
  130. calculated.  If i is 1, which it is the first time through, then 
  131. we will be looking for the cube of 1+5 = 6, which will result in 
  132. 216. When using CUBE, we group the values like this, 
  133. (1+5)*(1+5)*(1+5) = 6*6*6 = 216.  However, when we use WRONG, we 
  134. group them as 1+5*1+5*1+5 = 1+5+5+5 = 16 which is a wrong answer.  
  135. The parentheses are therefore required to properly group the 
  136. variables together.  It should be clear to you that either CUBE 
  137. or WRONG would arrive at a correct answer for a single term 
  138. replacement such as we did in the last program.  The correct 
  139. values of the cube and the square of the numbers are printed out 
  140. as well as the wrong values for your inspection. 
  141.  
  142. In line 7 we define the macro ADD_WRONG according to the above 
  143. rules but we still have a problem when we try to use the macro in 
  144. lines 25 and 26.  In line 26 when we say we want the program to 
  145. calculate 5*ADD_WRONG(i) with i = 1, we get the result 5*1 + 1 
  146. which evaluates to 5 + 1 or 6, and this is most assuredly not 
  147. what we had in mind.  We really wanted the result to be 5*(1 + 1) 
  148. = 5*2 = 10 which is the answer we get when we use the macro named 
  149. ADD_RIGHT, because of the extra parentheses around the entire 
  150. expression in the definition given in line 8.  A little time 
  151. spent studying the program and the result will be worth your 
  152. effort in understanding how to use macros.
  153.  
  154. In order to prevent the above problems, most experienced C 
  155. programmers include parentheses around each variable in a macro 
  156. and additional parentheses around the entire expression.  This 
  157. will allow any macro to work correctly.
  158.  
  159. The remainder of the program is simple and will be left to your 
  160. inspection and understanding.
  161.  
  162.  
  163. CONDITIONAL COMPILATION - PART 1
  164. -----------------------------------------------------------------
  165. The example program named IFDEF.C is our first    ===============
  166. illustration of a conditional compilation.            IFDEF.C
  167. OPTION_1 is defined in line 4, and is             ===============
  168. considered defined for the entire program.  
  169. Therefore when the preprocessor gets to line 6, it keeps the text 
  170. between lines 6 and 8 in the program and passes it to the 
  171. compiler.  If OPTION_1 was not defined when we reach line 6, the 
  172.  
  173.                                                          Page 6-3
  174.  
  175.                                    Chapter 6 - The C Preprocessor
  176.  
  177. preprocessor would throw away line 7 and the compiler would never 
  178. see it.  Likewise line 17 is conditionally compiled based on 
  179. whether OPTION_1 is defined or not.  This is a very useful 
  180. construct, but not the way we are using it here.  Generally it is 
  181. used to include a feature if we are using a certain processor, a 
  182. certain operating system, or even a special piece of hardware.
  183.  
  184. You should compile and execute the program as is, then comment 
  185. out line 4 so that OPTION_1 will not be defined, and recompile 
  186. and execute the program.  You will see that the extra line will 
  187. not be printed because it will be thrown away by the 
  188. preprocessor.  Keep in mind that the preprocessor does only 
  189. textual substitution or text removal and you will be able to use 
  190. it effectively.
  191.  
  192. Line 23 illustrates an undefine command to the preprocessor.  
  193. This removes the fact that OPTION_1 was defined and from this 
  194. point on, the program acts as though it were never defined.  Of 
  195. course, it does no good here since the program is completed and 
  196. there are no executable statements following the undefine, but it 
  197. does illustrate the undefine statement.
  198.  
  199. You should move the undefine to line 5, recompile and execute the 
  200. program, and you will see that it acts as though OPTION_1 was 
  201. never defined.
  202.  
  203.  
  204. CONDITIONAL COMPILATION - PART 2
  205. -----------------------------------------------------------------
  206. The next example program illustrates the         ================
  207. preprocessor directive which includes code if        IFNDEF.C
  208. a symbol in not defined.  The ifndef directive   ================
  209. reads literally, "if not defined", and with 
  210. that much definition, its operation should be intuitive.  This 
  211. program will be a real exercise in logic for the diligent student, 
  212. but should be understandable with a little effort.  The symbol 
  213. OPTION_1 is reversed from the last program and the symbol 
  214. PRINT_DATA is used to enable printing if it is not defined.  If 
  215. it is not defined, there will be some printout.  This example 
  216. program, much like the last one, is rather silly but illustrates 
  217. the use of preprocessor directives.  The next program is a little 
  218. more practical.
  219.  
  220.  
  221. CONDITIONAL COMPILATION - PART 3
  222. -----------------------------------------------------------------
  223. The program named DEBUGEX.C is a good           =================
  224. illustration of a very practical use of the         DEBUGEX.C
  225. preprocessor.  In this program we define a      =================
  226. symbol named MY_DEBUG at the beginning of the 
  227. program.  When we reach the code in the main program we see why 
  228. it is defined.  Apparently we do not have enough information to 
  229. complete this code, so we sort of slopped it in until we have a 
  230.  
  231.                                                          Page 6-4
  232.  
  233.                                    Chapter 6 - The C Preprocessor
  234.  
  235. chance to talk to Bill and Linda about how to do these 
  236. calculations.  In the meantime, we wish to continue work on other 
  237. parts of the program, so we use the preprocessor to temporarily 
  238. throw away this uncompilable code for us.  Because of the 
  239. obnoxious message we put into line 14, it will be impossible for 
  240. us to forget about the bad state of affairs we left the code in, 
  241. so we are forced to come back later and clean it up.
  242.  
  243. In this case, we are only concerned with a few lines of code, but 
  244. it could be a large block of code we are working with.  We could 
  245. also be using this technique to handle several large blocks of 
  246. code, some of which are in other modules, until Bill returns to 
  247. explain the analysis and we can complete the undefined blocks.
  248.  
  249.  
  250. MULTIPLE FILE PROGRAMS
  251. -----------------------------------------------------------------
  252. For very small programs, it is expedient to include all of the 
  253. code in a single file, and compile that one file for the final 
  254. resulting code.  It is not generally acceptable to do this 
  255. because all but the most trivial programs are too big to place 
  256. in a single file because the file gets to be very cumbersome to 
  257. work with.  It is not at all unusual for a C program to be made 
  258. up of over a thousand source files.  It is, of course, necessary 
  259. for these files to communicate and work together as one large 
  260. program.
  261.  
  262. Even though it is best not to use global variables, a variable 
  263. that is defined outside of any function, it is sometimes 
  264. expedient to use a few.  Sometimes these variables need to be 
  265. referenced by two or more different files, and C provides a way 
  266. to do this.  Consider the following three file portions.
  267.     
  268.   FILE1.C               FILE2.C               FILE3.C
  269. int index;            extern int index;     extern int index;
  270. extern int count;     int count;
  271.                       static int value;     int value;
  272.                       int main();
  273. static void one();    void two();           void three();
  274.  
  275. The variable named index declared in FILE1.C is available to any 
  276. other file for use because it is declared globally.  The other 
  277. two files make use of the same variable by declaring it as an 
  278. extern variable.  In essence, they are telling the compiler, "I 
  279. wish to use the variable named index which is defined somewhere 
  280. else".  Anytime index is referred to in either of the other two 
  281. files, the variable of that name is used from FILE1.C, and it can 
  282. be read, or modified by any of the three files.  This provides an 
  283. easy way to pass data from any file to any other file, but it 
  284. could lead to problems.  It would be very easy for any of these 
  285. files to modify index in some way not meant to and corrupt the 
  286. data.  It could be very difficult to determine which file 
  287. corrupted the value of index.
  288.  
  289.                                                          Page 6-5
  290.  
  291.                                    Chapter 6 - The C Preprocessor
  292.  
  293.  
  294. The variable named count is defined in FILE2.C and referred to in 
  295. the same manner defined above within FILE1.C, but is not 
  296. available for use in FILE3.C because it is not declared in it.  A 
  297. static variable, such as value in FILE2.C cannot be referenced in 
  298. any other file but is hidden in the declaring file by definition.  
  299. A completely separate variable named value is declared in FILE3.C 
  300. that has nothing to do with the same named variable in FILE2.C.  
  301. In this case, FILE1.C could declare value as an external variable 
  302. and refer to that variable in FILE3.C if desired.
  303.  
  304. The main() entry point can only be called by the operating system 
  305. to get the program started, but the functions two() and three() 
  306. can be called from anywhere within the three files because they 
  307. are global functions.  The function one() however, because it is 
  308. declared static, can only be called from within the file in which 
  309. it is declared.  It cannot be called from within FILE2.C or 
  310. FILE3.C.  It is sometimes expedient to "hide" a function within a 
  311. file, and it is often referred to as a local function as opposed 
  312. to being a global function.
  313.  
  314.  
  315. WHAT IS AN ENUMERATION VARIABLE?
  316. -----------------------------------------------------------------
  317. Load and display the program named ENUM.C for    ================
  318. an example of how to use the enum type                ENUM.C
  319. variable.  Line 6 contains the first enum type   ================
  320. variable named result which is a variable that 
  321. can take on any of the values contained within the braces.  
  322. Actually the variable result is an int type variable but can be 
  323. assigned any of the values defined for an int type variable.  The 
  324. names within the parentheses are int type constants and can be 
  325. used anywhere it is legal to use an int type constant.  The 
  326. constant WIN is assigned the value of 0, TIE the value 1, BYE the 
  327. value 2, etc.
  328.  
  329. In use, the variable named result is used just like any int 
  330. variable would be used as can be seen by its use in the program.  
  331. The enum type of variable is intended to be used by you, the 
  332. programmer, as a coding aid since you can use a constant named 
  333. MON for control structures rather than the meaningless (at least 
  334. to you) value of 1.  Notice that days is assigned the values of 
  335. days of the week in the remainder of the program.  If you were to 
  336. use a switch statement, it would be much more meaningful to use 
  337. the labels SUN, MON, etc, rather than the more awkward 0, 1, 2, 
  338. etc.
  339.  
  340. All caps are used for the enumeration values in this program as a 
  341. matter of personal taste because they are all constants.  There 
  342. is no universal standard on this matter and each programmer is 
  343. free to do as he wishes.  All caps for these values tends to be 
  344. standard practice however. 
  345.  
  346.  
  347.                                                          Page 6-6
  348.  
  349.                                    Chapter 6 - The C Preprocessor
  350.  
  351. WHAT IS A PRAGMA?
  352. -----------------------------------------------------------------
  353. A pragma is an instruction to your compiler to perform some 
  354. particular action at compile time.  Although pragmas vary from 
  355. compiler to compiler and are not standardized, they perform some 
  356. useful functions.  Your compiler probably supports some way for 
  357. you to select the optimization method by inserting a pragma into 
  358. the source code.  If your compiler provides a source listing 
  359. file, you probably have pragmas to format the output listing to 
  360. your personal preference.  Check your documentation for the 
  361. pragmas that are provided by your compiler.
  362.  
  363.  
  364. PROGRAMMING EXERCISE
  365. -----------------------------------------------------------------
  366. 1.  Write a program to count from 7 to -5 by counting down. Use 
  367.     #define statements to define the limits. (Hint, you will need 
  368.     to use a decrementing variable in the third part of the for 
  369.     loop control.
  370.  
  371.  
  372.  
  373.  
  374.  
  375.  
  376.  
  377.  
  378.  
  379.  
  380.  
  381.  
  382.  
  383.  
  384.  
  385.  
  386.  
  387.  
  388.  
  389.  
  390.  
  391.  
  392.  
  393.  
  394.  
  395.  
  396.  
  397.  
  398.  
  399.  
  400.  
  401.  
  402.  
  403.  
  404.  
  405.                                                          Page 6-7
  406.